package com.liuyu2783.redislock.annotation;

import com.liuyu2783.redislock.exception.RedisLockException;
import com.liuyu2783.redislock.service.CacheKeyGenerator;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Calendar;

/**
 * com.liuyu2783.redislock.annotation
 *
 * @author liuyu07
 * @date 2019-6-27
 */
@Aspect
@Configuration
public class LockMethodInterceptor {

    @Autowired
    private RedisLock redisLock;
    @Autowired
    private CacheKeyGenerator cacheKeyGenerator;
    @Autowired
    private StringRedisTemplate lockRedisTemplate;

    private static final Logger logger = LoggerFactory.getLogger(LockMethodInterceptor.class);

    @Around("execution(public * *(..)) && @annotation(com.liuyu2783.redislock.annotation.CacheLock)")
    public Object interceptor(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        CacheLock lock = method.getAnnotation(CacheLock.class);
        if (StringUtils.isEmpty(lock.prefix())) {
            throw new RedisLockException("-11", "redis锁的key不能为空");
        }
        final String lockKey = cacheKeyGenerator.getLockKey(pjp);
        String time = String.valueOf(Calendar.getInstance().getTimeInMillis()+lock.expire());

        final Boolean success = lockRedisTemplate.opsForValue().setIfAbsent(lockKey, time);
        if(!success){
            logger.error("请勿重复请求：lockKey={}, method={}", lockKey, method.getName());
            throw new RedisLockException("-10", "请勿重复请求");
        }else{
            logger.error("获取锁：lockKey={}, method={}", lockKey, method.getName());
        }
        try {
            return pjp.proceed();
        } catch (Throwable throwable) {
            logger.error("系统异常",throwable);
            throw new RedisLockException("-20", "系统异常");
        }finally {
            lockRedisTemplate.delete(lockKey);
            logger.error("执行完成释放锁。lockKey={}",lockKey);
        }
    }
}
